package com.hcc.flow.server.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import com.alibaba.fastjson.JSONObject;
import com.hcc.flow.server.common.utils.HttpHelper;
import com.hcc.flow.server.common.utils.StringUtilsV2;
import com.hcc.flow.server.config.BodyReaderHttpServletRequestWrapper;
import com.hcc.flow.server.model.common.AuthenticationBean;
import com.hcc.flow.server.model.common.ValidateCodeException;
import com.hcc.flow.server.service.sys.RedisServer;

/**
 * @author 韩长长 
 * @version createTime：2020年6月9日 下午4:40:48
 * 
 */

@Component
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
	/**
	 * 登录失败处理器
	 */
	@Autowired
	private AuthenticationFailureHandler failureHandler;
	
	private static final Logger log = LoggerFactory.getLogger("adminLogger");
	
	@Override
	public void afterPropertiesSet() throws ServletException {
		super.afterPropertiesSet();
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		boolean action = false;
		// 只拦截登录
		if (request.getRequestURI().equals("/login")) {
			action = true;
			if(request.getParameterMap().keySet().contains("nochek")){
				action = false;
			}
		}
		
		// 拦截请求
		if (action) {
			// 如果是登录请求
			try {
				ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
				String json = HttpHelper.getBodyString(requestWrapper);
				validate(json);
				filterChain.doFilter(requestWrapper, response);
				// filterChain.doFilter(request, response);
			} catch (ValidateCodeException exception) {
				// 返回错误信息给 失败处理器
				failureHandler.onAuthenticationFailure(request, response, exception);
				return;
			}
		} else {
			// 不做任何处理，调用后面的 过滤器
			filterChain.doFilter(request, response);
		}
	}

	private void validate(String content) {
		if (content.contains("param") && content.contains("{")) {
			JSONObject jsonObject = JSONObject.parseObject(content);
			content = jsonObject.get("param").toString();
		}

		String desCon = content;

		if (StringUtilsV2.isNotBlank(desCon)) {
			// 转化成认证对象
			AuthenticationBean authenticationBean = null;
			try {
				authenticationBean = JSONObject.parseObject(desCon, AuthenticationBean.class);
			} catch (Exception e) {
				log.error("原始已解密数据：{}", desCon);
				log.error("将解密的数据转为验证对象时失败,失败原因：{}", e.getMessage());
			}
			if (authenticationBean != null) {
				String strRes = ValidateCode(authenticationBean);
				if (!"1".equals(strRes)) {
					throw new ValidateCodeException(strRes);
				}
			} else {
				throw new ValidateCodeException("无法获取到验证码信息");
			}
		} else {
			throw new ValidateCodeException("无法获取到验证码的解密信息");
		}
	}

	public String ValidateCode(AuthenticationBean auth) {
		String strRes = "1";
		String verifyId = auth.getVerifyId();
		try {
			if (StringUtilsV2.isBlank(verifyId)) {
				strRes = "传入验证码ID为空";
			}
			Object captchaValue = RedisServer.getCacheValue("login-code", verifyId);
			if (captchaValue == null || StringUtilsV2.isBlank(captchaValue.toString())) {
				strRes = "验证码已过期";
			} else {
				if (!captchaValue.toString().equalsIgnoreCase(auth.getVerifyCode())) {
					strRes = "验证码错误";
				} else {
					RedisServer.remove("login-code", verifyId);
				}
			}
		} catch (Exception e) {
			strRes = "异常错误：" + e.getMessage();
		}
		return strRes;

	}

	/**
	 * 失败 过滤器 getter and setter 方法
	 */
	public AuthenticationFailureHandler getFailureHandler() {
		return failureHandler;
	}

	public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
		this.failureHandler = failureHandler;
	}
}
